В ADA университете студенты
очень любят соревнования по программированию, поэтому каждый студент входит в
одну (и только одну) команду. Но правила разных соревнований разные, и не
всегда одна команда состоит из 3 человек, как по правилам ACM. В любой команде
может быть любое количество студентов (но конечно более 0).
Студенты любят приходить в
свою столовую, которая находится в корпусе C, и проводить свободное время за
чашкой кофе. Студенты в ADA очень умные, не хотят стоять в стандартной очереди
за вкусным кофе. Они решили установить некоторые правила, которым будут
следовать только они.
Когда студент становится в
очередь, он сначала просматривает очередь с начала до конца, чтобы проверить,
находятся ли уже в очереди некоторые из его товарищей по команде (студенты из
его же команды). Если да, то он встает в очередь сразу за ними (позади всех
своих товарищей по команде). В противном случае он становится в конец очереди и
становится новым последним элементом (невезение). Удаление из очереди
выполняется как и в обычных очередях: студенты обрабатываются с начала до конца
в том же порядке, в котором они стоят в очереди.
Вам следует написать
программу, имитирующую такую очередь.
Вход. Первая строка содержит количество команд t (1 ≤ t ≤ 1000). Каждая из следующих t строк описывает одну команду. Первый элемент в строке – это
количество n (1 ≤ n ≤ 1000) студентов в
команде. Далее в строке следуют n целых
чисел, задающих идентификаторы (0 ≤ ID ≤ 106)
учащихся в одной команде.
Далее следует список команд.
Имеется два разных типа команд:
·
ENQUEUE x –
студент x становится в
очередь;
·
DEQUEUE – обработка первого студента в очереди и
удаление его;
Выход. Для каждой
команды DEQUEUE выведите в отдельной строке номер удаляемого
студента.
Пример входа 1 |
Пример выхода 1 |
2 3 1 2 3 3 4 5 6 ENQUEUE 1 ENQUEUE 4 ENQUEUE 2 ENQUEUE 5 ENQUEUE 6 ENQUEUE 3 DEQUEUE DEQUEUE DEQUEUE DEQUEUE DEQUEUE DEQUEUE |
1 2 3 4 5 6 |
|
|
Пример входа 2 |
Пример выхода 2 |
2 3 1 2 3 3 4 5 6 ENQUEUE 1 ENQUEUE 4 ENQUEUE 2 DEQUEUE DEQUEUE ENQUEUE 5 ENQUEUE 3 ENQUEUE 6 DEQUEUE DEQUEUE DEQUEUE DEQUEUE |
1 2 4 5 6 3 |
Пример входа 3 |
Пример выхода 3 |
3 3 11 12 13 3 24 25 26 3 47 48 49 ENQUEUE 11 ENQUEUE 47 ENQUEUE 48 ENQUEUE 12 ENQUEUE 24 ENQUEUE 49 DEQUEUE DEQUEUE DEQUEUE ENQUEUE 13 DEQUEUE DEQUEUE DEQUEUE |
11 12 47 48 49 24 |
очередь
Для
каждого студента следует запомнить номер команды, которой он принадлежит. Пусть
teamBelongTo[ID] содержит номер
команды, которой принадлежит студент с идентификатором ID (ID ≤ 106).
int teamBelongTo[1000001];
Объявим
массив очередей teamQueue.
queue<int> teamQueue[1001];
В
каждую очередь входят только участники одной команды. Команд не более 1000.
Команды будем нумеровать с 0.
Студенты в очереди будут всегда стоять по группам
(командам). Объявим общую очередь combinedQueue,
которая содержит номера команд групп студентов, стоящих в очереди.
queue<int> combinedQueue;
Рассмотрим
выполнение команды ENQUEUE n. Определим команду team, которой принадлежит студент n. Если в очереди нет ни одного
студента из команды team, то студент номер n
становится в конец общей очереди. Представители команды team становятся
в конец общей очереди combinedQueue. Добавляем студента номер n в конец
очереди teamQueue[team].
Рассмотрим
выполнение команды DEQUEUE. В голове combinedQueue находится номер команды team студента, стоящего первым в очереди. Извлекаем студента из очереди.
Если это был последний студент из команды (teamQueue[team] становится пустой), то
удаляем голову очереди combinedQueue.
Пример
Рассмотрим
третий тест. Имеются три команды. Массив teamBelongTo имеет
вид:
-
команда 0 состоит из участников 11, 12, 13;
-
команда 1 состоит из участников 24, 25, 26;
-
команда 2 состоит из участников 47, 48, 49;
Промоделируем
первые 5 команд (все они имеют тип ENQUEUE). Общая очередь имеет вид (сверху возле каждого ID студента указан его номер команды):
Массив
очередей teamQueue имеет вид:
Общая
очередь combinedQueue
имеет вид:
Она
означает, что в общей очереди сначала стоит группа студентов из команды 0,
потом группа из команды 2 и в конце группа из команды 1.
Поступила
команда ENQUEUE
49. Вычисляем
какой команде принадлежит студент с ID = 49:
teamBelongTo[49] = 2. Следует проверить, есть ли представители команды
номер 2 в общей очереди. Для этого надо проверить, не пустая ли очередь teamQueue[2]. Нет, она не пустая, следовательно с
очередью combinedQueue делать ничего не нужно. Студент с ID = 49 будет занесен в конец очереди teamQueue[2], теперь станет teamQueue[2] = {47, 48, 49}.
Массив
очередей teamQueue имеет вид:
Далее
следуют три команды DEQUEUE.
При выполнениее первых двух команд из очереди удаляются студенты с номарами 11
и 12. Как только очередь teamQueue[0] станет пустой, номер команды 0 следует удалить из головы
очереди combinedQueue. Третьим из очереди уйдет студент
с ID = 47.
Состояние
очередей примет вид:
Массив
очередей teamQueue имеет вид:
Следующая
команда ENQUEUE
13. Студент с ID = 13 принадлежит команде номер teamBelongTo[13] = 0.
Представителей команды номер 0 в очереди нет (teamQueue[0] пустая). Следовательно номер команды 0
следует занести в конец очереди combinedQueue. Обновим teamQueue[0] = {13}.
Массив
очередей teamQueue имеет вид:
Реализация алгоритма
Для
каждого студента следует запомнить номер коанды, которой он принадлежит. Пусть teamBelongTo[ID] содержит номер
команды, которой принадлежит студент с идентификатором ID.
int teamBelongTo[1000001];
Объявим
массив очередей teamQueue. В каждую
очередь входят только участники одной команды. Команд не более 1000.
queue<int> teamQueue[1001];
Читаем количество команд numTeams.
Команды будем нумеровать с 0.
cin >> numTeams;
for (t = 0; t < numTeams; t++)
{
Чистим очередь команды номер t.
while (!teamQueue[t].empty()) teamQueue[t].pop();
Читаем данные команды номер t. В команде
номер t
находится numElem участников.
cin >> numElem;
while (numElem--)
{
cin >> elem;
Участник номер elem принадлежит
команде номер t.
teamBelongTo[elem] = t;
}
}
Объявим общую очередь combinedQueue, которая
содержит номера команд групп студентов, стоящих в очереди.
queue<int> combinedQueue;
Обрабатываем команды до конца файла.
while (cin >> command)
{
Пришел студент номер num. Вставка в очередь.
if (command[0] == 'E')
{
cin >> num;
Студент номер num принадлежит команде team.
team = teamBelongTo[num];
Если в очереди нет ни одного студента из команды team,
то студент номер num становится в конец общей очереди.
Представители команды team становятся в конец общей очереди combinedQueue.
if (teamQueue[team].empty())
combinedQueue.push(team);
Добавляем студента номер num в конец очереди teamQueue[team].
teamQueue[team].push(num);
}
else
{
В голове combinedQueue находится номер команды team студента, стоящего первым в очереди. Извлекаем студента из очереди.
Если это был последний студент из команды (teamQueue[team] становится пустой), то
удаляем голову очереди combinedQueue.
team = combinedQueue.front();
cout << teamQueue[team].front()
<< '\n';
teamQueue[team].pop();
if (teamQueue[team].empty())
combinedQueue.pop();
}
}